
 
import { priority } from 'utils/constants/definetypes';
import {   factoryBlacklist, FactoryLevel, FactoryState, FactoryTransportType } from './constants'
import { generateUniqueId } from 'utils/utils';
 
export class FactoryTaskHelper
{
    private static CommodityCompose:Record<CommodityConstant,Record<ResourceConstant,number>>= {} as any;
    static getProduceTask(room:string, resourceType: CommodityConstant,amount:number,p:number=priority.D)
    {
      
      const task:ITask<IFactoryTaskData<"produce">>={
          id:generateUniqueId(),
          priority:p,
          ttl:-1,
          type:"factory",
          data:{
              type:"produce",
              arg: FactoryTaskHelper.getProduceTaskArg(resourceType,amount),
          },
          shard: 1,
      }
      return task;
    }

   static Top(task:IFactoryTask):ITargetParam|undefined
   {
      if(task.ProduceList.length == 0)
      {
        return undefined;
      }
      return task.ProduceList[task.ProduceList.length-1];
   }
   static Pop(task:IFactoryTask):ITargetParam|undefined
   {
      if(task.ProduceList.length == 0)
      {
        return undefined;
      }
    //   if(task.ProduceList.length==1)
    //   {
    //     task.TopTask.amount = task.ProduceList[0].amount;
    //   }
      return task.ProduceList.pop();
   }
   static Push(task:IFactoryTask,ResourceTarget:ITargetParam)
   {
        task.ProduceList.push(ResourceTarget);
   }

   static PushTransport(task:IFactoryTask,ResourceTarget:ITargetParam)
   {
        task.TransportList.push(ResourceTarget);
   }
   static CalAllSubResourceAmount(targetResource: CommodityConstant | MineralConstant | RESOURCE_GHODIUM | RESOURCE_ENERGY, targetAmount: number): Record<FactoryResourceType,number>
   {
       const submap:Record<string,number>={};
       const subconstants = COMMODITIES[targetResource].components;
       for(const subconstant in  subconstants)
       {
            const amount = this.ClacSubResourceAmount(targetResource as CommodityConstant,targetAmount,subconstant as FactoryResourceType);
            submap[subconstant]=amount;
       }
       return submap;
    }

    static CalAllProduceAmount(targetResource: CommodityConstant | MineralConstant | RESOURCE_GHODIUM | RESOURCE_ENERGY):number
    {
        const submap:Record<string,number>={};
        COMMODITIES[targetResource].amount
        const subconstants = COMMODITIES[targetResource].components;
        return  Math.max(COMMODITIES[targetResource].amount, _.sum(Object.values(subconstants)))
     }

   static ClacSubResourceAmount(targetResource: CommodityConstant, targetAmount: number, subResource: FactoryResourceType): number {
    const subResources = COMMODITIES[targetResource].components
    // 目标数量除于单次合成数量，向上取整后乘以单次合成所需的材料数量
    return subResources[subResource] * Math.ceil(targetAmount / COMMODITIES[targetResource].amount)
    }
    static SwitchState(task:IFactoryTask,state:FactoryState)
    {
        task.state = state;
    }


    static getProduceTaskArg(targetResource: CommodityConstant, targetAmount: number)
    {
      const arg:ITargetParam = {
        target:targetResource,
        amount:targetAmount
        ,number:0
      };
      const producetask:IFactoryTask={
        isInit:false,
        state:FactoryState.Prepare,
        TopTask:arg,
        ProduceList:[_.clone(arg)],
        TransportList:[]
      };
      return producetask;
    }

 
    public static CreateProductStack(task:IFactoryTask)
    {
        const topProduce =task.TopTask;
        const ProduceList :ITargetParam[]=[topProduce];
        this.CreateChildProduceList(topProduce,ProduceList);
        task.ProduceList = ProduceList;
        return task;
    }

    public static CreateChildProduceList(preTask:ITargetParam,ProduceList :ITargetParam[],isrecursion:boolean = true)
    {
      const subResources = COMMODITIES[preTask.target].components;
      for (const resType in subResources)
      {
        const currestype = resType as FactoryResourceType;
        if (factoryBlacklist.includes(resType as MineralConstant) || !(resType in COMMODITIES)) continue;
        const needAmount = FactoryTaskHelper.ClacSubResourceAmount(preTask.target, preTask.amount,currestype);
        const childtarget :ITargetParam= {target:currestype as CommodityConstant,amount:needAmount,number:0};
        ProduceList.push(childtarget);
        if(isrecursion)
        {
            this.CreateChildProduceList(childtarget,ProduceList,isrecursion);
        }

      }
      return
    }


    public static getProductComposeRecord(resourceType:CommodityConstant,time:number=1)
    {
        if(this.CommodityCompose[resourceType])
        {
            return this.CommodityCompose[resourceType];
        }

        this.CommodityCompose[resourceType] = this.getProductCompose(resourceType,COMMODITIES[resourceType].amount*time);
        return this.CommodityCompose[resourceType];
    }
    private static getProductCompose(resourceType:CommodityConstant,amount:number):Record<ResourceConstant,number>
    {
        if( factoryBlacklist.includes(resourceType) ||!COMMODITIES[resourceType] || !COMMODITIES[resourceType].components)
        {
            return {[resourceType]:amount} as any
        }
        const childresmap = this.CalAllSubResourceAmount(resourceType,amount);
        const childrecord :Record<string,number>={} as any;
        for(const key in childresmap)
        {
            const subchild = this.getProductCompose(key as CommodityConstant , childresmap[key as FactoryResourceType]);
            for(const k in subchild)
            {
                if(childrecord[k])
                {
                    childrecord[k] += subchild[k as ResourceConstant];
                }
                else
                {
                    childrecord[k] = subchild[k as ResourceConstant];
                }
            }

        }
        return childrecord;
    }
}
